www.gusucode.com > vc++ 远程控制示例源程序-源码程序 > vc++ 远程控制示例源程序-源码程序\code\PeerYouC\Compress.cpp
// Compress.cpp: implementation of the CCompress class. // Download by http://www.NewXing.com ////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "Compress.h" ////////////////////////////////////////////////////////////////////// // Construction/Destruction ////////////////////////////////////////////////////////////////////// CCompress::CCompress() { code_value=NULL; /* This is the code value array */ prefix_code=NULL; /* This array holds the prefix codes */ append_character=NULL; /* This array holds the appended chars */ decode_stack=NULL; /* This array holds the decoded string */ num_bits=INIT_BITS; /* Starting with 9 bit codes */ bytes_in=0,bytes_out=0; /* Used to monitor compression ratio */ input_bit_count=0; input_bit_buffer=0L; output_bit_count=0; output_bit_buffer=0L; checkpoint=CHECK_TIME; /* For compression ratio monitoring */ incounts=0; /* Input Bytes */ outcounts=0; /* Output Bytes */ counts=0; /* Statistic */ bFlagAlloc=false; } CCompress::~CCompress() { /*扫尾*/ if(code_value) code_value=(int*)GlobalFree(code_value); if(prefix_code) prefix_code=(unsigned int*)GlobalFree(prefix_code); if(append_character) append_character=(unsigned char*)GlobalFree(append_character); if(decode_stack) decode_stack=(unsigned char*)GlobalFree(decode_stack); bFlagAlloc=false; } /* MODIFIED This is the new compression routine. The first two 9-bit codes * have been reserved for communication between the compressor and expander. */ void CCompress::compress() { unsigned int next_code=FIRST_CODE; unsigned int character; unsigned int string_code; unsigned int index; int i, /* All purpose integer */ ratio_new, /* New compression ratio as a percentage */ ratio_old=100; /* Original ratio at 100% */ num_bits=INIT_BITS; /* Re-initialize for expansion */ max_code = MAXVAL(num_bits); for (i=0;i<TABLE_SIZE;i++){ /* Initialize the string table first */ code_value[i]=-1; } string_code=*input++; /* Get the first code */ incounts++; /* This is the main compression loop. Notice when the table is full we try * to increment the code size. Only when num_bits == MAX_BITS and the code * value table is full do we start to monitor the compression ratio. */ while(incounts<counts ) { character=*input++; incounts++; ++bytes_in; index=find_match(string_code,character); if (code_value[index] != -1) string_code=code_value[index]; else { if (next_code <= max_code ) { code_value[index]=next_code++; prefix_code[index]=string_code; append_character[index]=character; } output_code(string_code); /* Send out current code */ string_code=character; if (next_code > max_code) { /* Is table Full? */ if ( num_bits < MAX_BITS) { /* Any more bits? */ max_code = MAXVAL(++num_bits); /* Increment code size then */ } else if (bytes_in > checkpoint) { /* At checkpoint? */ if (num_bits == MAX_BITS ) { ratio_new = bytes_out*100/bytes_in; /* New compression ratio */ if (ratio_new > ratio_old) { /* Has ratio degraded? */ output_code(CLEAR_TABLE); /* YES,flush string table */ num_bits=INIT_BITS; next_code=FIRST_CODE; /* Reset to FIRST_CODE */ max_code = MAXVAL(num_bits); /* Re-Initialize this stuff */ bytes_in = bytes_out = 0; ratio_old=100; /* Reset compression ratio */ for (i=0;i<TABLE_SIZE;i++) /* Reset code value array */ code_value[i]=-1; } else /* NO, then save new */ ratio_old = ratio_new; /* compression ratio */ } checkpoint = bytes_in + CHECK_TIME; /* Set new checkpoint */ } } } } output_code(string_code); /* Output the last code */ if (next_code == max_code) { /* Handles special case for bit */ ++num_bits; /* increment on EOF */ } output_code(TERMINATOR); /* Output the end of buffer code */ output_code(0); /* Flush the output buffer */ output_code(0); output_code(0); } /* MODIFIED This is the modified expansion routine. It must now check for the * CLEAR_TABLE code and know when to increment the code size. */ void CCompress::uncompress() { unsigned int next_code=FIRST_CODE; unsigned int new_code; unsigned int old_code; int character, counter=0, clear_flag=1; /* Need to clear the code value array */ unsigned char *string; num_bits=INIT_BITS; /* Re-initialize for expansion */ max_code = MAXVAL(num_bits); while((new_code=input_code()) != TERMINATOR) { if (clear_flag) { /* Initialize or Re-Initialize */ clear_flag=0; old_code=new_code; /* The next three lines have been moved */ character=old_code; /* from the original */ *output++=(unsigned char)old_code; outcounts++; continue; } if (new_code == CLEAR_TABLE) { /* Clear string table */ clear_flag=1; num_bits=INIT_BITS; next_code=FIRST_CODE; max_code = MAXVAL(num_bits); continue; } if (++counter == 1000) { /* Pacifier */ counter=0; } if (new_code >= next_code) { /* Check for string+char+string */ *decode_stack=character; string=decode_string(decode_stack+1,old_code); } else string=decode_string(decode_stack,new_code); character = *string; /* Output decoded string in reverse */ while (string >= decode_stack){ *output++=*string--; outcounts++; } if (next_code <= max_code) { /* Add to string table if not full */ prefix_code[next_code]=old_code; append_character[next_code++]=character; if (next_code == max_code && num_bits < MAX_BITS) { max_code = MAXVAL(++num_bits); } } old_code=new_code; } } /* UNCHANGED from original * This is the hashing routine. */ int CCompress::find_match(unsigned int hash_prefix, unsigned int hash_character) { int index, offset; index = (hash_character << HASHING_SHIFT ) ^ hash_prefix; if (index == 0 ) offset=1; else offset = TABLE_SIZE - index; while(1) { if (code_value[index] == -1 ) return(index); if (prefix_code[index] == hash_prefix && append_character[index] == hash_character) return(index); index -= offset; if (index < 0) index += TABLE_SIZE; } } /* UNCHANGED from original * Decode a string from the string table, storing it in a buffer. * The buffer can then be output in reverse order by the expansion * program. */ unsigned char *CCompress::decode_string(unsigned char *buffer, unsigned int code) { int i=0; while(code > 255 ) { *buffer++ = append_character[code]; code=prefix_code[code]; if (i++ >= 4000 ) { /*一般不会错*/ ; } } *buffer=code; return(buffer); } /* UNCHANGED from original * Input a variable length code. */ unsigned CCompress::input_code() { unsigned int return_value; // static int input_bit_count=0; // static unsigned long input_bit_buffer=0L; while (input_bit_count <= 24 ) { input_bit_buffer |= (unsigned long) (*input++) << (24 - input_bit_count); incounts++; input_bit_count += 8; } return_value=input_bit_buffer >> (32-num_bits); input_bit_buffer <<= num_bits; input_bit_count -= num_bits; return(return_value); } /* MODIFIED Output a variable length code. */ void CCompress::output_code(unsigned int code) { // static int output_bit_count=0; // static unsigned long output_bit_buffer=0L; output_bit_buffer |= (unsigned long) code << (32 - num_bits - output_bit_count); output_bit_count += num_bits; while (output_bit_count >= 8) { *output++=(unsigned char)(output_bit_buffer >> 24); output_bit_buffer <<= 8; output_bit_count -= 8; bytes_out++; /* ADDED for compression monitoring */ outcounts++; } } bool CCompress::AllocTables() { bool flag=true; __try{ code_value=(int*)GlobalAlloc(GPTR,TABLE_SIZE*sizeof(unsigned int)); prefix_code=(unsigned int *)GlobalAlloc(GPTR,TABLE_SIZE*sizeof(unsigned int)); append_character=(unsigned char*)GlobalAlloc(GPTR,TABLE_SIZE*sizeof(unsigned char)); decode_stack=(unsigned char*)GlobalAlloc(GPTR,4000); bFlagAlloc=true; } __except(1){ if(code_value) code_value=(int*)GlobalFree(code_value); if(prefix_code) prefix_code=(unsigned int*)GlobalFree(prefix_code); if(append_character) append_character=(unsigned char*)GlobalFree(append_character); if(decode_stack) decode_stack=(unsigned char*)GlobalFree(decode_stack); flag=false; bFlagAlloc=false; } return flag; } void CCompress::FreeTables() { if(code_value) code_value=(int*)GlobalFree(code_value); if(prefix_code) prefix_code=(unsigned int*)GlobalFree(prefix_code); if(append_character) append_character=(unsigned char*)GlobalFree(append_character); if(decode_stack) decode_stack=(unsigned char*)GlobalFree(decode_stack); bFlagAlloc=false; } bool CCompress::init(unsigned char *inputs,unsigned long lens,unsigned char *outputs) { if(!bFlagAlloc) return false; input=inputs; output=outputs; counts=lens; num_bits=INIT_BITS; /* Starting with 9 bit codes */ max_code = MAXVAL(num_bits); bytes_in=0,bytes_out=0; /* Used to monitor compression ratio */ input_bit_count=0; input_bit_buffer=0L; output_bit_count=0; output_bit_buffer=0L; checkpoint=CHECK_TIME; /* For compression ratio monitoring */ incounts=0; outcounts=0; return true; } unsigned long CCompress::GetOutBytes() { return outcounts; } unsigned long CCompress::GetInBytes() { return incounts; }